home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK2.toast / Development Kits (Disc 2) / QuickTime / Programming Stuff / Documentation / develop articles / develop Issue 24 / Printing Compressed Images / PrintPICTtoJPEG / PrintPictToJPEG.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-19  |  20.9 KB  |  783 lines  |  [TEXT/MPCC]

  1. /*
  2.  * PrintPICTtoJPEG.c
  3.  
  4.     Authored by: David Gelphman 6/12/95. 
  5.     
  6.     This application opens PICT data files and images them into a 32 bit deep
  7.     offscreen bitmap. It then uses the offscreen bits as a source of bit image
  8.     data to compress and print using QuickTime image compression.
  9.     
  10.     Copyright (c) Apple Computer Incorporated. All rights reserved.
  11.  
  12. */
  13.  
  14. #include "PrintPICTtoJPEG.h"
  15.  
  16. /* globals  */
  17.  
  18. WindowPtr gTheWindow;
  19. PICTImage gThePICTImage;
  20. THPrint    gPrinterRecord = NULL;
  21. GWorldPtr    gTheOffscreenWorld;
  22. Boolean gDoImageCompression;
  23.  
  24. /* main */
  25. SInt16 main()
  26. {
  27. OSErr theErr;
  28.  
  29.     // initialize the managers and the menus
  30.     if (initMacintosh() != noErr)
  31.         return 0;
  32.  
  33.     /*  allocate a print record for us */
  34.     gPrinterRecord = (THPrint)NewHandle(sizeof( TPrint ) );
  35.  
  36.     // Get the defaults for the current printer driver.
  37.     if (gPrinterRecord != NULL && MemError() == noErr)
  38.     {
  39.         PrOpen(); 
  40.         PrintDefault( gPrinterRecord ); 
  41.         PrClose();
  42.     }else{
  43.         ParamText("\pCan't allocate Print Record.", "\p", "\p", "\p");
  44.         Alert(kGenericError, NULL);    
  45.         return iMemFullErr;    
  46.     }
  47.         
  48.     // Check to see if there are any errors and report them if they occur.
  49.     if(( theErr = PrError()) != noErr){
  50.         Str255 scratchString;
  51.         NumToString((long)theErr, scratchString);
  52.         ParamText("\pCan't Do PrDefault for some reason.", scratchString, "\p", "\p");
  53.         Alert(kGenericError, NULL);    
  54.     }
  55.     
  56.     // initialize our PICTImage Data Structure.
  57.     gThePICTImage.theData = NULL;
  58.     SetRect(&gThePICTImage.theBounds,0,0,0,0);
  59.     gThePICTImage.theDesc = NULL;
  60.  
  61.     // Go ahead and get an image...
  62.     DoTheOpenCommand();
  63.     
  64.     // Process events, etc.
  65.     for (; handleEvent();)
  66.         {
  67.         }    /* for */
  68.     return 1;    
  69.  
  70. } /* main */
  71.  
  72. //=====================================================================================
  73. // OSErr DrawBitImage(GWorldPtr theGWorld, Rect *bounds, Boolean doCompression)
  74. //=====================================================================================
  75. // Draws a Bitmap image from an offscreen GWorld.
  76. // If doCompression flag is true, then do compression, otherwise just do CopyBits.
  77. //=====================================================================================
  78.  
  79. OSErr DrawBitImage(GWorldPtr theGWorld, Rect *bounds, Boolean doCompression)
  80. {
  81.     OSErr theErr = noErr;
  82.     Boolean canDraw;
  83.     PixMapHandle sPixMap;
  84.     Boolean didDrawing = false;
  85.  
  86.     sPixMap = GetGWorldPixMap(theGWorld);    
  87.  
  88.     if(doCompression){
  89.         MatrixRecord theMatrix;
  90.         CQDProcs myStdProcs;
  91.         StdPixProcPtr MyProcPtr;
  92.         ImageDescriptionHandle theDescH;
  93.         Handle  compressedDataH = NULL;
  94.         long maxCompressionSize = 0;
  95.                         
  96.         // Lock the Pixels so we can draw from the PixMap
  97.         canDraw = LockPixels(sPixMap);
  98.  
  99.         if((theErr == noErr) && canDraw){ 
  100.             CodecType theCodecType = 'jpeg';
  101.             CodecComponent theCodec = (CodecComponent)anyCodec;
  102.             CodecQ    spatialQuality = codecNormalQuality;
  103.             short    depth = 32;
  104.  
  105.             if(theErr == noErr)theErr = GetMaxCompressionSize(sPixMap, bounds, depth,
  106.                                             spatialQuality, theCodecType,
  107.                                             theCodec, &maxCompressionSize);
  108.  
  109.             if(theErr == noErr){
  110.                 // this allocation should be no problem
  111.                 theDescH = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescriptionHandle));
  112.                 
  113.                 // this allocation is probably for a lot of memory
  114.                 compressedDataH = NewHandle(maxCompressionSize);
  115.                 theErr = MemError();
  116.  
  117.                 // See if we allocated the ImageDescriptionHandle but
  118.                 // not the memory to receive the compressed image.
  119.                 if((theDescH != NULL) && (theErr != noErr)){
  120.                     
  121.                     // see if we can get temp memory instead
  122.                     // Since we are going to use the temp memory as a real handle
  123.                     // we require System 7.0 or greater
  124.                    compressedDataH = TempNewHandle(maxCompressionSize, &theErr);
  125.                    // this probably can't happen but just in case...
  126.                    if(compressedDataH == NULL && theErr == noErr)theErr = iMemFullErr;
  127.                 }
  128.             }
  129.             
  130.             if((theErr == noErr) && (compressedDataH != NULL) && (theDescH != NULL)){
  131.                 MoveHHi(compressedDataH);
  132.                 HLock(compressedDataH);
  133.                                                     
  134.                 theErr = CompressImage(sPixMap, bounds, spatialQuality, theCodecType,
  135.                             theDescH,  StripAddress(*compressedDataH));
  136.                 HUnlock(compressedDataH);
  137.             }
  138.             
  139.         }
  140.         
  141.         // Unlock the pixels since we are done with them. 
  142.         UnlockPixels(sPixMap);
  143.         
  144.         if(theErr == noErr){
  145.             // we need a pixmap for our call to the StdPix bottleneck.
  146.             PixMapHandle SpecialPixMapH = NewPixMap();
  147.             PixMapPtr SpecialPixMapP;
  148.                     
  149.             if(SpecialPixMapH != NULL && MemError() == noErr){
  150.             
  151.                 HLock((Handle)SpecialPixMapH);
  152.                 HLock(compressedDataH);
  153.  
  154.                 SpecialPixMapP = (PixMapPtr)StripAddress(*(Handle)SpecialPixMapH);
  155.                     
  156.                 // This makes a compressed 'PixMap' structure into SpecialPixMap, using the
  157.                 // ImageDescription in 'theDescH' with the compressed image data in 'compressedDataH'
  158.                 theErr = SetCompressedPixMapInfo(SpecialPixMapP, theDescH, StripAddress(*compressedDataH), 0,NULL,NULL);
  159.                 
  160.                 // The data in compressedDataH needs to be locked during the StdPix proc call below.
  161.                 // We only unlock the data after we're done with the StdPix call.
  162.  
  163.                 if(theErr == noErr){                            
  164.                     // set both flag bits described in IM QuickTime p.3-139 for StdPix
  165.                     short flags = kCallOldBits | kCallStdBits;        
  166.  
  167.                     // make a matrix which describes the mapping between the source
  168.                     // and destination rectangles. In our case, they will be the
  169.                     // same rectangle
  170.                     RectMatrix(&theMatrix, bounds, bounds);
  171.                                                                                 
  172.                     // Look to see if there are custom QuickDraw bottlenecks in the current port.
  173.                     if( (((CGrafPtr)qd.thePort)->grafProcs) == NULL){
  174.                         // Get the Standard Bottleneck procs. 
  175.                         SetStdCProcs(&myStdProcs);
  176.                         
  177.                         // The 'newProc1' bottleneck is the 'StdPix' bottleneck.
  178.                         MyProcPtr = (StdPixProcPtr)myStdProcs.newProc1;
  179.                         
  180.                     }else{
  181.                         // Use the custom 'StdPix' bottleneck in the grafPort.
  182.                         MyProcPtr = (StdPixProcPtr)((CGrafPtr)qd.thePort)->grafProcs->newProc1;
  183.                     }
  184.                     
  185.                     // Call the bottleneck. The function call being used here is:
  186.                     // StdPix(SpecialPixMapP, &srcRect, &theMatrix, ditherCopy, NULL, NULL,NULL,flags)
  187.                     // with the appropriate StdPix bottleneck.
  188.                     CallStdPixProc(MyProcPtr,SpecialPixMapP, bounds, &theMatrix, 
  189.                         ditherCopy, NULL, NULL,NULL,flags );
  190.     
  191.                     didDrawing = true;
  192.                 }
  193.                 HUnlock(compressedDataH);
  194.                 HUnlock((Handle)SpecialPixMapH);
  195.                     
  196.             }
  197.             if(SpecialPixMapH)DisposePixMap(SpecialPixMapH);
  198.         }
  199.         if(compressedDataH)DisposeHandle(compressedDataH);
  200.         if(theDescH)DisposeHandle((Handle)theDescH);
  201.  
  202.     }
  203.     
  204.     if(!didDrawing){
  205.         /* backup in case:
  206.              (1) we couldn't do drawing before because there wasn't enough memory to compress the data.    OR
  207.              (2) We were called without a request to do image compression. This is done here when we are
  208.                  not printing or we are printing to a grafPort which doesn't support color and therefore
  209.                  does not support the StdPix bottleneck.
  210.         */
  211.         canDraw = LockPixels(sPixMap);
  212.         if(canDraw){
  213.             OSErr qdErr;
  214.             CopyBits( & (((GrafPtr)theGWorld)->portBits),
  215.                       & (((GrafPtr)qd.thePort)->portBits),
  216.                       bounds, bounds,
  217.                       ditherCopy, NULL);
  218.             if( (qdErr = QDError()) != noErr){
  219.                 ParamText("\pNot Enough Memory To Handle this Image", "\p", "\p", "\p");
  220.                 Alert(kGenericError, NULL);    
  221.             }
  222.         }
  223.         UnlockPixels(sPixMap);
  224.     }
  225.     return theErr;
  226. }    /* DrawBitImage */
  227.  
  228.  
  229.  
  230.  
  231. static void DoTheOpenCommand()
  232. {
  233. OSErr theErr = noErr;
  234. OSType theTypes[] = { 'PICT' };
  235. StandardFileReply theReply;
  236. Rect bounds;
  237. SInt16 windowTop = GetMBarHeight()+ 19;
  238. SInt16 right,bottom;
  239.  
  240.     // check to see if we already have data. If so, we'll dispose of it since we are going to open a new image.
  241.     if( gThePICTImage.theData != NULL){
  242.         DisposeHandle((Handle)gThePICTImage.theData);
  243.         gThePICTImage.theData = NULL;
  244.     }
  245.         
  246.     if(gTheOffscreenWorld != NULL){
  247.         DisposeGWorld(gTheOffscreenWorld);
  248.         gTheOffscreenWorld = NULL;
  249.     }
  250.  
  251.     // disable the Print menu item since we can't print data anymore.
  252.     DisableItem(GetMHandle(kFileMenuID), kPrintCommand);    
  253.  
  254.     // Hide the existing window, if there is one.
  255.     if(gTheWindow != NULL)HideWindow(gTheWindow);
  256.  
  257.     // Get a PICT file and read the data.
  258.     if(theErr == noErr){
  259.         StandardGetFile(NULL, 1, theTypes, &theReply);
  260.         if (theReply.sfGood) {
  261.             theErr = ReadPICTData(&(theReply.sfFile),(Handle *)&(gThePICTImage.theData) );
  262.             if(theErr != noErr){
  263.                 ParamText("\pNot Enough Memory To Read this Image Into Memory.", "\p", "\p", "\p");
  264.                 Alert(kGenericError, NULL);    
  265.             }
  266.         }else {
  267.             // no file selected so just return.
  268.             return;
  269.         };
  270.     };
  271.     
  272.     // Set the bounds field in the PICTData structure
  273.     if (theErr == noErr) theErr = SetPICTBounds(&gThePICTImage);
  274.  
  275.     // Make an offscreen GWorld that is 32 bits deep and the size of the PICT bounding rect
  276.     // Make sure the Pixels aren't purgeable so we can unload the PICT data after
  277.     // we image the PICT into the offscreen buffer.
  278.     
  279.     if(theErr == noErr)theErr = NewGWorld(&gTheOffscreenWorld, 32, &gThePICTImage.theBounds, 
  280.                 NULL, NULL,0);    // flags are: pixels not purgeable and create a new device
  281.             
  282.     if(theErr == iMemFullErr) {
  283.         ParamText("\pCan't Allocate the Offscreen GWorld.", "\p", "\p", "\p");
  284.         Alert(kGenericError, NULL);    
  285.     }    
  286.     
  287.     // Now make a Window of an appropriate size to hold our image. If we already
  288.     // have a window then size it properly.
  289.  
  290.  
  291.     // Max out the Window size at approximately the main screen size.    
  292.     
  293.     if (theErr == noErr) {
  294.         right = MIN(gThePICTImage.theBounds.right , qd.screenBits.bounds.right - kInsetBits );
  295.         bottom = MIN(gThePICTImage.theBounds.bottom, qd.screenBits.bounds.bottom - (kInsetBits+windowTop) );
  296.         SetRect(&bounds, 0 ,0 , right, bottom);
  297.     }
  298.     
  299.     if (theErr == noErr){
  300.         
  301.         OffsetRect(&bounds, 0, windowTop);
  302.  
  303.         if(gTheWindow == NULL) {
  304.             gTheWindow = NewCWindow(NULL, &bounds,    
  305.                     (StringPtr)&(theReply.sfFile.name),
  306.                     false, noGrowDocProc, (WindowPtr)-1, true, 0);
  307.             if (gTheWindow == NULL) {
  308.                 theErr = iMemFullErr;    
  309.             }
  310.         } else{
  311.             MoveWindow (gTheWindow, 0, windowTop, true);    
  312.             SetWTitle(gTheWindow, theReply.sfFile.name);
  313.             SizeWindow (gTheWindow, bounds.right - bounds.left, bounds.bottom-bounds.top, true);
  314.         }
  315.     }
  316.     
  317.     if (theErr == noErr) {
  318.         AlignWindow(gTheWindow, true, NULL, NULL);
  319.         ShowWindow(gTheWindow);
  320.         SetPort(gTheWindow);
  321.         OffsetRect(&bounds, 0, -windowTop);
  322.         ClipRect(&bounds);
  323.     };
  324.     
  325.     // Now draw the PICT into the Offscreen Buffer.
  326.     if( theErr == noErr){
  327.         CGrafPtr saveCPort;
  328.         GDHandle saveDevice;
  329.         Boolean canDraw;
  330.         PixMapHandle sPixMap;
  331.         
  332.         // save the existing Port and Device
  333.         GetGWorld(&saveCPort, &saveDevice);
  334.         
  335.         // make the current drawing world our offscreen world
  336.         SetGWorld(gTheOffscreenWorld,NULL);
  337.  
  338.         sPixMap = GetGWorldPixMap(gTheOffscreenWorld);    
  339.         
  340.         // Lock the PixMap so we can draw.
  341.         canDraw = LockPixels(sPixMap);
  342.         
  343.         // Only draw if the return result from LockPixels is true
  344.         if(canDraw){
  345.             EraseRect(&(gTheOffscreenWorld->portRect));
  346.             DrawPicture(gThePICTImage.theData,&gThePICTImage.theBounds);
  347.             
  348.             // We don't need the PICT Data anymore so get rid of it.
  349.             DisposeHandle((Handle)gThePICTImage.theData);
  350.             gThePICTImage.theData = NULL;
  351.  
  352.         }
  353.         // Unlock the Pixels now that we're done drawing
  354.         UnlockPixels(sPixMap);
  355.  
  356.         // reset the saved Port and Device
  357.         SetGWorld(saveCPort,saveDevice);
  358.     }
  359.  
  360.     // Since we have an image, we'll enable the 'Print' menu item.    
  361.     if (theErr == noErr) EnableItem(GetMHandle(kFileMenuID), kPrintCommand);
  362.     
  363.     // Invalidate the Window contents so we'll get an update event.
  364.     if( theErr == noErr)InvalRect(&gTheWindow->portRect);
  365.     
  366.      DrawMenuBar();
  367.         
  368.  }    /* DoTheOpenCommand */
  369.  
  370.  
  371.     
  372. // Initialize the World and check whether the appropriate managers are available.
  373. static OSErr initMacintosh()
  374. {
  375.     long version;
  376.     OSErr theErr = noErr;
  377.        
  378.     InitGraf(&qd.thePort);
  379.     InitFonts();
  380.     InitWindows();
  381.     FlushEvents(everyEvent, 0);
  382.       InitDialogs(NULL);
  383.     TEInit();
  384.     InitCursor();
  385.     SetFractEnable(true);            // I guess this urge comes from my old days at Adobe
  386.     
  387.     theErr = SetupMenus();
  388.     
  389.     if(theErr != noErr){
  390.         ParamText("\pCouldn't load Menus.", "\p", "\p", "\p");
  391.     }
  392.  
  393.     if(theErr == noErr){
  394.         theErr = Gestalt(gestaltSystemVersion, &version);
  395.         if( (theErr != noErr) || (version < 0x0700) ){
  396.                 ParamText("\pThis software requires System 7.0 or higher.", "\p", "\p", "\p");
  397.                 theErr = kAppError;
  398.         }
  399.     }    
  400.  
  401.     if(theErr == noErr){
  402.         theErr = Gestalt(gestaltQuickTimeVersion, &version);
  403.         if( (theErr != noErr) ){
  404.                 ParamText("\pQuickTime not installed.  This demo requires Quicktime.", "\p", "\p", "\p");
  405.         }
  406.     }    
  407.     
  408.     if(theErr == noErr){
  409.         theErr = Gestalt(gestaltCompressionMgr, &version);
  410.         if( (theErr != noErr) ){
  411.                 ParamText("\pThe Image compression manager is not available. This can't continue!", "\p", "\p", "\p");
  412.         }
  413.     }    
  414.  
  415.     
  416.     if ( theErr == noErr) {        // make sure there is a Codec available that can handle JPEG.
  417.         CodecInfo theInfo;
  418.         
  419.         theErr = GetCodecInfo(&theInfo, 'jpeg', anyCodec);
  420.         if(theErr != noErr)ParamText("\pThere don't appear to be any JPEG decompressors!", "\p", "\p", "\p");        
  421.     }
  422.     
  423.     if(theErr != noErr){
  424.         Alert(kGenericError, NULL);    
  425.     }
  426.     
  427.     gTheOffscreenWorld = NULL;
  428.  
  429.     gDoImageCompression = true;
  430.     CheckItem(GetMHandle(kImageCompressionMenuID), kDoImageCompression,gDoImageCompression);
  431.         
  432.     return theErr;
  433. }    /* initMacintosh */
  434.  
  435.  
  436. static SInt16 handleEvent()
  437. {
  438.     EventRecord e;
  439.     WindowRecord *w;
  440.     SInt32 s;
  441.     Rect b;
  442.     RgnHandle currentGrayRegion;
  443.     OSErr theErr;
  444.     GrafPtr oldPort;
  445.     
  446.     if (WaitNextEvent(everyEvent, &e, kSleepTime, 0L))
  447.         {
  448.         switch (e.what)
  449.             {
  450.             case mouseDown:
  451.                 switch (FindWindow(e.where, (WindowPtr *)&w))
  452.                     {
  453.                     case inContent:
  454.                         if ((WindowRecord *) FrontWindow() != w)
  455.                             SelectWindow((WindowPtr)w);
  456.                         else if (((WindowRecord *) w)->windowKind < 0)
  457.                             SystemClick(&e, (WindowPtr )w);
  458.                         break;
  459.                     case inDrag:
  460.                         currentGrayRegion = GetGrayRgn();
  461.                         b = (**(RgnHandle)currentGrayRegion).rgnBBox;
  462.                         // make sure drags align well for best performance.
  463.                         DragAlignedWindow((WindowPtr )w, e.where, &b, NULL, NULL);
  464.                         break;
  465.                     case inGoAway:
  466.                         if (TrackGoAway((WindowPtr )w, e.where)){
  467.                             HideWindow((WindowPtr )w);
  468.                             DisableItem(GetMHandle(kFileMenuID), kPrintCommand);
  469.                             DrawMenuBar();
  470.                         }
  471.                         break;
  472.                     case inGrow:
  473.                         SetRect(&b, 30, 30, 0x7fff, 0x7fff);
  474.                         s = GrowWindow((WindowPtr )w, e.where, &b);
  475.                         if (s){
  476.                             SizeWindow((WindowPtr )w, LoWord(s), HiWord(s), 1);
  477.                             SetPort((WindowPtr )w);
  478.                             InvalRect(&gTheWindow->portRect);
  479.                         }
  480.                         break;
  481.                     case inZoomIn:
  482.                         if (TrackBox((WindowPtr )w, e.where, inZoomIn)){
  483.                             ZoomWindow((WindowPtr )w, inZoomIn, 0);
  484.                             SetPort((WindowPtr )w);
  485.                             InvalRect(&gTheWindow->portRect);
  486.                         }
  487.                         break;
  488.                     case inZoomOut:
  489.                         if (TrackBox((WindowPtr )w, e.where, inZoomOut)){
  490.                             ZoomWindow((WindowPtr )w, inZoomOut, 0);
  491.                             SetPort((WindowPtr )w);
  492.                             InvalRect(&gTheWindow->portRect);
  493.                         }
  494.                         break;
  495.                     case inMenuBar: 
  496.                     {
  497.                         SInt32 mResult = MenuSelect(e.where);
  498.                           SInt16 theMenu, theItem;
  499.                           theMenu = HiWord(mResult); 
  500.                           theItem = LoWord(mResult);
  501.                         doCommand(theMenu, theItem);
  502.                           break;
  503.                       }
  504.                 }
  505.                 break;
  506.             case updateEvt:
  507.                 if((WindowPtr)e.message == gTheWindow){
  508.                     BeginUpdate((WindowPtr)e.message);
  509.     
  510.                     GetPort(&oldPort);
  511.                     SetPort((WindowPtr)e.message);
  512.                         
  513.                     theErr = DrawBitImage(gTheOffscreenWorld,&(gThePICTImage.theBounds),kNoCompression);
  514.                     
  515.                     SetPort(oldPort);
  516.                     EndUpdate((WindowPtr)e.message);
  517.                 }
  518.                 break;
  519.             case keyDown:
  520.               case autoKey:
  521.                 DoKeyDown(&e);
  522.                 break;
  523.               default: break;
  524.  
  525.             }    /* switch */
  526.         }    /* if */
  527.     return 1;
  528. }    /* handleEvent */
  529.  
  530.  
  531. static OSErr SetupMenus(void) 
  532. {
  533.     OSErr theErr = noErr;
  534.     Handle MyMBar;
  535.         
  536.     MyMBar = GetNewMBar(128);
  537.     if(MyMBar) {
  538.         SetMenuBar(MyMBar);
  539.         AddResMenu(GetMHandle(kAppleMenuID),'DRVR');
  540.         DisableItem(GetMHandle(kFileMenuID), kPrintCommand);
  541.  
  542.         DrawMenuBar();
  543.     } else {
  544.         theErr = kCouldntLoadMenu;
  545.     }
  546.     return theErr;
  547. } /* SetupMenus */
  548.  
  549.  
  550. static void DoKeyDown(myEvent) 
  551.     EventRecord *myEvent; 
  552. {
  553.  
  554.     unsigned char charCode = (unsigned char) (myEvent->message & charCodeMask);
  555.     
  556.     if (myEvent->modifiers & cmdKey) 
  557.       { /* command key */
  558.         SInt32 mResult = MenuKey(charCode);
  559.         SInt16 theMenu = HiWord(mResult); /* This is the resource ID */
  560.         SInt16 theItem = LoWord(mResult);
  561.         doCommand(theMenu, theItem);
  562.     }
  563.     return ;
  564. }    /* DoKeyDown */
  565.  
  566.  
  567. /*
  568.    Display the About dialog.
  569. */
  570. static void showAboutMeDialog() 
  571. {
  572.   GrafPtr savePort;
  573.   SInt16 itemHit;
  574.   DialogPtr theDialog;
  575.  
  576.   GetPort(&savePort);
  577.   theDialog = GetNewDialog(kAboutMeDLOG, NULL, (WindowPtr) -1);
  578.   SetPort(theDialog);
  579.  
  580.   do { ModalDialog(NULL, &itemHit); } while (itemHit != kOKButton);
  581.  
  582.   CloseDialog(theDialog);
  583.  
  584.   SetPort(savePort);
  585.   return;
  586. }    /* showAboutMeDialog */
  587.  
  588.  
  589. /*
  590.  * Process Menu Selections
  591. */
  592. static void doCommand(SInt16 theMenu,SInt16 theItem)
  593. {
  594. OSErr theErr = noErr ;
  595.  
  596.       switch (theMenu) 
  597.       {
  598.         case kAppleMenuID:
  599.           if (theItem == kAboutMeCommand) 
  600.           {
  601.                 showAboutMeDialog();
  602.           }
  603.           else 
  604.           {
  605.             GrafPtr savePort;
  606.             Str255 daName;
  607.             GetItem(GetMHandle(kAppleMenuID), theItem, daName);
  608.             GetPort(&savePort);
  609.             (void) OpenDeskAcc(daName);
  610.             SetPort(savePort);
  611.           }
  612.           break;
  613.     
  614.         case kFileMenuID:
  615.           switch (theItem) 
  616.           {
  617.             case kOpenCommand:
  618.                 DoTheOpenCommand();
  619.                 break;
  620.             case kSaveCommand:
  621.                 break;
  622.             case kPageSetupCommand:                            
  623.                 PrOpen();
  624.                 theErr = PrError();
  625.                     
  626.                 if(theErr == noErr ){
  627.                     PrValidate( gPrinterRecord );
  628.                     theErr = PrError();    
  629.                 }
  630.  
  631.                 if(theErr == noErr){
  632.                     PrStlDialog(gPrinterRecord);
  633.                     theErr = PrError();
  634.                 }
  635.                 PrClose();
  636.                 
  637.                 if(theErr != noErr){
  638.                     Str255 scratchString;
  639.                     NumToString((long)theErr, scratchString);
  640.                     ParamText("\pThere was a print manager error.", scratchString, "\p", "\p");
  641.                     Alert(kGenericError, NULL);    
  642.                 }
  643.                 break;
  644.             case kPrintCommand:
  645.                 theErr = Print(gThePICTImage, gPrinterRecord);
  646.                 if(theErr != noErr){
  647.                     Str255 scratchString;
  648.                     NumToString((long)theErr, scratchString);
  649.                     ParamText("\pThere was an error during printing.", scratchString, "\p", "\p");
  650.                     Alert(kGenericError, NULL);    
  651.                 }
  652.                 break;
  653.             case kQuitCommand:                
  654.                 ExitToShell();
  655.                 break;
  656.             default:
  657.                 break;
  658.           }
  659.           break;
  660.     
  661.         case kEditMenuID:
  662.           /*
  663.            * Run this through SystemEdit first.
  664.            * SystemEdit will return FALSE if it's not a system window.
  665.            */
  666.           if (SystemEdit(theItem-1)) break;
  667.         
  668.         case kImageCompressionMenuID:
  669.           switch (theItem) 
  670.           {
  671.             case kDoImageCompression:
  672.                 gDoImageCompression = !gDoImageCompression;
  673.                 CheckItem(GetMHandle(kImageCompressionMenuID), kDoImageCompression,gDoImageCompression);
  674.                 break;
  675.             default:
  676.                 break;
  677.           }
  678.           break;
  679.  
  680.         default:
  681.           break;
  682.         } /*endswitch theMenu*/
  683.     
  684.       HiliteMenu(0);
  685.       return;
  686. } /* DoCommand */
  687.  
  688.  
  689. static OSErr Print(PICTImage thePICTImage,  THPrint  thePrintRecord)
  690. {
  691. OSErr theDrawingErr = noErr;
  692. OSErr aPrintingErr = noErr;
  693.  
  694. GrafPtr oldPort;
  695. TPrStatus thePrinterStatus;
  696. TPPrPort PrinterPort;
  697. Boolean OKToPrint;
  698.  
  699.     GetPort( &oldPort ); 
  700.             
  701.     PrOpen();
  702.         
  703.     if( PrError() == noErr){
  704.         PrValidate(thePrintRecord);
  705.         if( PrError() == noErr){
  706.             OKToPrint = PrJobDialog(thePrintRecord);
  707.             if(OKToPrint){
  708.                 PrinterPort = PrOpenDoc(thePrintRecord,NULL,NULL);
  709.                 if(PrError() == noErr){
  710.                     PrOpenPage(PrinterPort,NULL);
  711.                     if(PrError() == noErr){
  712.                         // Only do Compression if the Port is a Color Port
  713.                         theDrawingErr = DrawBitImage(gTheOffscreenWorld,&(thePICTImage.theBounds),
  714.                             ( gDoImageCompression && ISCOLORPORT((GrafPtr)PrinterPort)) );
  715.                     }
  716.                     PrClosePage(PrinterPort);
  717.                 }
  718.                 PrCloseDoc(PrinterPort);
  719.                 if( 
  720.                     ( (*thePrintRecord)->prJob.bJDocLoop == bSpoolLoop ) && 
  721.                     ( PrError() == noErr )
  722.                 ){
  723.                     PrPicFile(thePrintRecord,NULL,NULL,NULL, &thePrinterStatus);
  724.                 }
  725.             }
  726.         } 
  727.     }
  728.     aPrintingErr = PrError();
  729.     PrClose();
  730.     SetPort(oldPort);
  731.     if(theDrawingErr != noErr) {
  732.         Str255 scratchString;
  733.         NumToString((long)theDrawingErr, scratchString);
  734.         ParamText("\pCouldn't do compression.", scratchString, "\p", "\p");
  735.         Alert(kGenericError, NULL);    
  736.     }
  737.     return ( aPrintingErr) ;
  738. } /* Print */
  739.  
  740.  
  741. // Read the PICT data from the file into a Handle
  742. static OSErr ReadPICTData(FSSpec *theSpec, Handle *theData)
  743. {
  744.     short refNum;
  745.     OSErr theErr;
  746.     long size;
  747.     
  748.     theErr = FSpOpenDF(theSpec, fsRdPerm, &refNum);
  749.     if (theErr == noErr) {
  750.         // position the file at the start
  751.         theErr = SetFPos(refNum, fsFromStart, 0);
  752.         // determine the total size of the file
  753.         if(theErr == noErr)theErr = GetEOF(refNum, &size);
  754.         if (theErr == noErr) {
  755.             // skip PICT header
  756.             size -= kPICTHeaderSize;        
  757.             theErr = SetFPos(refNum, fsFromStart, kPICTHeaderSize);
  758.         }
  759.         if (theErr == noErr) {
  760.             if ((*theData = NewHandle(size)) && (MemError() == noErr) ) {
  761.                 HLock(*theData);
  762.                 theErr = FSRead(refNum, &size, **theData);
  763.                 HUnlock(*theData);
  764.             } else theErr = memFullErr;
  765.         }
  766.         FSClose(refNum);
  767.     }
  768.     return theErr;
  769. }
  770.  
  771. static  OSErr SetPICTBounds(PICTImage *thePICTImage)
  772. {
  773.     long theLen ;
  774.     unsigned char *theData;
  775.     short theCode;
  776.     Rect *theBounds = &(*thePICTImage).theBounds;
  777.     
  778.     *theBounds =  (*(*thePICTImage).theData)->picFrame;
  779.     return noErr;
  780. }    /* ReadPICTData */
  781.  
  782.  
  783.